/** io.c: implements io sycalls
 *
 * Author: 	Nora Tarano <ntarano@andrew.cmu.edu>
 *          Yuan Meng <yuanm@andrew.cmu.edu>
 *          Yipeng Yun <yipengy@andrew.cmu.edu>
 * Date: 	Dec 11, 2011
 */
#include <types.h>
#include <exports.h>
#include <bits/errno.h>
#include <bits/fileno.h>

#include <arm/physmem.h>
#include <kernel.h>

// Special characters
#define EOT 0x4
#define BACKSPACE 0x8
#define DELETE 127
#define NEWLINE 0xa
#define RETURN 0xd

// Read syscall: reads count bytes from stdin and echoes them in buf
ssize_t read_syscall(int fd, void *buffer, size_t count)
{
	unsigned int bufIndex;
	char tempChar;
	char * buf = (char *)buffer;

	// check for argument errors
	if (fd != STDIN_FILENO)
		return -EBADF;
	if (!valid_addr(buffer, count, RAM_START_ADDR, RAM_END_ADDR))
		return -EFAULT;
		
	// reading procedure
	for (bufIndex = 0; bufIndex < count; ++bufIndex) {
		// read char from stdin
		tempChar = getc();
		// interpret special characters
		if (tempChar == EOT)
			return bufIndex;
		if (tempChar == BACKSPACE || tempChar == DELETE) {
			bufIndex--;
			buf[bufIndex] = 0; 
			bufIndex--;
			puts("\b \b");
			continue;
		}
		// store and display read character
		buf[bufIndex] = tempChar;
		putc(buf[bufIndex]);
		// interpret newline / carriage return characters
		if (buf[bufIndex] == NEWLINE || buf[bufIndex] == RETURN)
		{
			putc('\n');
			return bufIndex + 1;
		}
	}
	
	return bufIndex;
}

// Write syscall: writes count bytes from buf to stdout
ssize_t write_syscall(int fd, const void *buffer, size_t count)
{
	unsigned int bufIndex;
	char *buf = (char *) buffer;
	
	// check for argument errors
	if (fd != STDOUT_FILENO)
		return -EBADF;
	if (!valid_addr(buffer, count, RAM_START_ADDR, RAM_END_ADDR) &&
		!valid_addr(buffer, count, FLASH_START_ADDR, FLASH_END_ADDR))
		return -EFAULT;
	
	// output buf to stdout
	for (bufIndex = 0; bufIndex < count; bufIndex++)
		putc(buf[bufIndex]);
	
	return count;
}
